package com.lam.common.base.domain.tree;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.lam.common.utils.CollectionUtil;
import com.lam.common.utils.NumberUtil;
import com.lam.common.utils.StringUtils;

public class TreeUtil {
	
	/**
	 * 构建菜单树结构, 不检查父节点
	 * @param list
	 * @return
	 */
	@SuppressWarnings({ "rawtypes"})
	public static <T extends BaseTree> List<T> buildTree(List<T> list){
		return buildTree(list, false, null);
	}
	
	/**
	 * 构建菜单树结构, 检查父节点
	 * @param list
	 * @return
	 */
	@SuppressWarnings({ "rawtypes"})
	public static <T extends BaseTree> List<T> buildTree(List<T> list, String topId){
		return buildTree(list, true, topId);
	}

	/**
	 * 构建菜单树结构
	 * @param list
	 * @param checkParent 是否检查父节点存在
	 * @param topId 顶层节点父Id
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T extends BaseTree> List<T> buildTree(List<T> list, boolean checkParent, String topId){
		
		if(CollectionUtil.isEmpty(list)) {
			return list;
		}
		
		Map<String, T> menuMap = new HashMap<>(list.size());
		for (T t : list) {
			menuMap.put(t.getId(), t);
		}
		
		T pMenu;
		T t;
		Iterator<T> it = list.iterator();
		while (it.hasNext()) {
			t = it.next();
			pMenu = menuMap.get(t.getParentId());
			if(pMenu != null){
				pMenu.addChild(t);
				it.remove();
			}else {
				if(checkParent && !isTopNode(topId, t.getParentId())) {
					it.remove();
				}
			}
		}
		
		setDeep(list, 0);
		sort(list, (t1, t2)->NumberUtil.compare(t1.getSortNo(), t2.getSortNo()));
		return list;
	}
	
	public static boolean isTopNode(String topId, String parentId) {
		return StringUtils.equals(topId, parentId);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static <T extends BaseTree> void sort(List<T> list, Comparator<T> c) {
		if(CollectionUtil.isNotEmpty(list)) {
			Collections.sort(list, c);
			for (T tt : list) {
				sort(tt.getChildren(), c);
			}
		}
		
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private static <T extends BaseTree> void setDeep(List<T> list, int deep) {
		for (T tt : list) {
			tt.setElementDeep(deep);
			if(CollectionUtil.isNotEmpty(tt.getChildren())) {
				setDeep(tt.getChildren(), deep+1);
			}
		}
	}
}
